#pragma once

#include "ThreadCache.h"
#include "CentralCache.h"
#include <algorithm>
static int count1;
void* ThreadCache::Allocate(size_t size)
{
	assert(size > 0 && size <= MAX_BYTES);

	size_t alignSize = SizeClass::RoundUp(size);
	size_t index = SizeClass::Index(size);

	std::cout << "alignsize: " << alignSize << "index: " << index << std::endl;
	if (!_freeList[index].Empty())
	{
		std::cout << "count1: " << (++count1) << std::endl;
		//std::cout << "ThreadCache.cpp 16 " << "if" << std::endl;
		return _freeList[index].Pop();
	}
	else
	{
		//std::cout << "ThreadCache.cpp 21 " << "else" << std::endl;

		return FetchFromCentralCache(index, alignSize);
	}
}

void ThreadCache::Deallocate(void* ptr, size_t size)
{
	assert(ptr);
	assert(size > 0 && size <= MAX_BYTES);
	size_t index = SizeClass::Index(size);
	_freeList[index].Push(ptr);

	// 当链表长度大于一次批量申请的内存时就还一段list给centralcache
	if (_freeList[index].getSize() >= _freeList[index].GetMaxSize())
	{
		ListTooLong(_freeList[index], size);
	}
}
void* ThreadCache::FetchFromCentralCache(size_t index, size_t size)
{
	// 慢开始反馈调节算法
	// 1.最开始不会一次向centralcache要太多，因为要太多了可能用不完
	// 2.如果你不要size大小的，就会一直申请，导致BatchNum一直增大到上限
	// 3.size越大，分配的BatchNum就会越小
	// 4.size越小，分配的BatchNum就会越大

	//第一次申请就只给一个size大小的对象，后续申请再多给

	size_t BatchNum = min(_freeList[index].GetMaxSize(), size);

	if (BatchNum == _freeList[index].GetMaxSize())
	{
		_freeList[index].GetMaxSize() += 1;
	}

	void* start = nullptr, * end = nullptr;


	size_t ActualGetObjNum = CentralCache::GetCCacheInstance().FetchRangeObj(start, end, BatchNum, size);

	//一个都没返回说明程序写错了或者中心缓存也没空间了，又或者系统没空间了
	assert(ActualGetObjNum > 0);

	if (ActualGetObjNum == 1)
	{
		//这里为什么要断言？查看FetchRangeObj的逻辑就知道，如果spanlist是空的，start和end就是相等的
		//如果没有进循环，最后返回的就是1，spanlist是空的，没有空间可分配，程序就错了
		assert(start == end);
		//std::cout << "ThreadCache.cpp 65 " << "else" << std::endl;
		return start;
	}
	else
	{
		//std::cout << "ThreadCache.cpp 71 " << "else" << std::endl;
		_freeList[index].PushRange(ChangeOneToTwoPointer(start), end, ActualGetObjNum - 1);


		return start;
	}
}

void ThreadCache::ListTooLong(FreeList& list, size_t size)
{
	void* start = nullptr;
	void* end = nullptr;
	list.PopRange(start, end, list.GetMaxSize());
	CentralCache::GetCCacheInstance().ReleaseListToSpans(start, size);
}